﻿using System;

namespace DevOnServer
{
    public static class CPacketCreator
    {
        public static CPacket weather(Weather weather)
        {
            _startShared(0);

            switch (weather)
            {
                case Weather.Rain:
                    _addPart(-1, Part.WeatherRain);
                    m_packet.addInt(1);
                    break;

                case Weather.Snow:
                    _addPart(-1, Part.WeatherSnow);
                    m_packet.addInt(1);
                    break;

                default:
                    _addPart(-1, Part.WeatherNormal);
                    m_packet.addInt(0);
                    break;
            }

            _finish();

            return m_packet;
        }

        public static CPacket levelInfos(CPlayerObject obj)
        {
            _startShared(0);

            _addPart(obj.ID, Part.LevelInfos);

            CCharacter character = obj.Player.Character;

            m_packet.addLong(character.Exp);
            m_packet.addUShort((ushort)character.Level);
            m_packet.addInt(character.Level);
            m_packet.addInt(character.SkillPoints);
            m_packet.addLong(0); // death exp
            m_packet.addUShort(0); // death level

            _finish();

            return m_packet;
        }

        public static CPacket updateItem(CPlayerObject obj, byte slot, UpdateItemType type, int data, int card = 0)
        {
            _startShared(0);

            _addPart(obj.ID, Part.InventoryUpdateItem);

            m_packet.addByte(0);
            m_packet.addByte(slot);
            m_packet.addByte((byte)type);
            m_packet.addShort((short)data);
            m_packet.addShort((short)card);

            _finish();

            return m_packet;
        }

        public static CPacket revival(CPlayerObject obj)
        {
            _startShared(0);

            _addPart(obj.ID, Part.Revival);

            _finish();

            return m_packet;
        }

        public static CPacket moveItem(CPlayerObject obj, byte oldPos, byte newPos)
        {
            _startShared(0);

            _addPart(obj.ID, Part.InventoryMoveItem);

            m_packet.addByte(0);
            m_packet.addByte(oldPos);
            m_packet.addByte(newPos);

            _finish();

            return m_packet;
        }

        public static CPacket moverDeath(CMover killed)
        {
            _startShared(0);

            _addPart(killed.ID, Part.MoverDeath);

            _finish();

            return m_packet;
        }

        public static CPacket damage(CCreature attacker, CCreature target, int damage, int flags)
        {
            _startShared(0);

            _addPart(target.ID, Part.Damage);

            m_packet.addInt(attacker.ID);
            m_packet.addInt(damage);
            m_packet.addInt(flags);

            _finish();

            return m_packet;
        }

        public static CPacket attack(CCreature attacker, CCreature target, int motion)
        {
            _startShared(0);

            _addPart(attacker.ID, Part.AttackMotion);

            m_packet.addInt(motion);
            m_packet.addInt(target.ID);
            m_packet.addInt(0);
            m_packet.addInt(0x10000);

            _finish();

            return m_packet;
        }

        public static CPacket worldBegin(CGamePlayer player)
        {
            CPlayerObject obj = player.Object;
            CCharacter character = player.Character;
            CAccount account = player.Account;

            _startShared(obj.ID, 0x0000ff00);

            _addPart(obj.ID, Part.Spawn);

            m_packet.addByte(5); // type d'objet
            m_packet.addInt(character.Sex == Sex.Female ? 12 : 11); // model
            m_packet.addByte(5); // type d'objet
            m_packet.addInt(character.Sex == Sex.Female ? 12 : 11);  // model
            m_packet.addShort(obj.Size); // taile (multipliée par 100)
            m_packet.addPosition(obj.Position); // position
            m_packet.addShort(obj.Rotation); // rotation
            m_packet.addInt(obj.ID); // ID de l'objet

            m_packet.addShort(1); // motion
            m_packet.addByte(1); // 1 s'il s'agit d'un joueur
            m_packet.addInt(obj.HP); //HP
            m_packet.addInt(0); // state|motion
            m_packet.addInt(0); // flags du state
            m_packet.addByte(1); // belligerence

            m_packet.addInt(-1); // V15 : SFX pour les bébés buffeurs

            m_packet.addString(character.Name); // nom du perso
            m_packet.addByte((byte)character.Sex); // sexe (masculin = 0|féminin = 1)
            m_packet.addByte(0); // skinset -> semble ne plus être utilisé
            m_packet.addByte(character.Hair); // ID des cheveux
            m_packet.addInt(character.HairColor); // couleur des cheveux
            m_packet.addByte(character.Head); // ID de la tête
            m_packet.addInt(character.ID); // ID du perso
            m_packet.addByte((byte)character.Job); // classe
            m_packet.addShort((short)character.FOR); // STR
            m_packet.addShort((short)character.END); // STA
            m_packet.addShort((short)character.DEX); // DEX
            m_packet.addShort((short)character.INT); // INT
            m_packet.addShort((short)character.Level); // level
            m_packet.addInt(-1); // fuel
            m_packet.addInt(0); // accfuel

            // partie guilde
            m_packet.addByte(0); // 1 si le joueur a une guilde
            m_packet.addInt(0); // cape de la guilde

            // partie groupe
            m_packet.addByte(0); // 1 si le joueur a un groupe

            m_packet.addByte((byte)account.AccessLevel); // accesslevel
            m_packet.addInt(0); // flags
            m_packet.addInt(0); // state mode
            m_packet.addInt(0x000001F6); // ???
            m_packet.addInt(0); // PK time
            m_packet.addInt(0); // PK
            m_packet.addInt(0); // PK propensity
            m_packet.addInt(0); // PK exp
            m_packet.addInt(0); // réputation
            m_packet.addByte(0); // si 1 le joueur est en duel
            m_packet.addInt(-1); // titre honorifique

            for (int i = 0; i < 31; i++)
                m_packet.addInt(0); // m_aEquipInfo[i].nOption

            m_packet.addInt(0); // m_nGuildCombatState

            for (int i = 0; i < 26; i++)
                m_packet.addInt(0); // m_dwSMTime[j]

            m_packet.addShort((short)obj.MP); // mana
            m_packet.addShort((short)obj.FP); // fp

            m_packet.addInt(0); // stade du tutoriel débutant de pang

            m_packet.addInt(0); // experience de vol
            m_packet.addInt(15000); // penya
            m_packet.addLong(character.Exp); // experience

            m_packet.addInt(0); // m_nSkillLevel
            m_packet.addInt((short)character.SkillPoints); // m_nSkillPoint

            m_packet.addLong(0); // m_nDeathExp
            m_packet.addInt(0); // m_nDeathLevel

            for (int i = 0; i < 32; i++)
                m_packet.addInt(0); // dwJobLv

            m_packet.addInt(1); // ID de la map de résurrection
            m_packet.addPosition(new CVec3Df(5583.189453f, 75.226776f, 3891.419434f)); // point de résurrection

            m_packet.addByte(0); // nombre de quêtes
            m_packet.addByte(0); // nombre de quêtes terminées
            m_packet.addByte(0); // nombre de quêtes cochées

            m_packet.addInt(0); // m_idMurderer

            m_packet.addShort((short)character.StatPoints); // stat points
            m_packet.addShort(0);

            for (int i = 0; i < 31; i++)
                m_packet.addInt(-1); // m_aEquipInfo[i].dwId

            // skills
            for (int i = 0; i < 45; ++i)
            {
                m_packet.addInt(-1);
                m_packet.addInt(0);
            }

            m_packet.addByte(0); // points de réputation à donner
            m_packet.addInt(1000 * 60 * 60 * 1); // temps avant le prochain point de réputation (inutile)

            m_packet.addByte(0); // slot du perso

            // penya de chaque perso en banque
            for (int i = 0; i < 3; i++)
                m_packet.addInt(0);

            // ID de chaque perso à la banque
            m_packet.addInt(player.Character.ID);
            m_packet.addInt(-1);
            m_packet.addInt(-1);

            m_packet.addInt(0); // m_nPlusMaxHitPoint
            m_packet.addByte(255);  // m_nAttackResistLeft;				
            m_packet.addByte(255);  // m_nAttackResistRight;				
            m_packet.addByte(255);  // m_nDefenseResist;

            m_packet.addLong(0); // experience de l'ange pour le PK
            m_packet.addInt(0); // level de l'ange

            for (int i = 0; i < 73; i++)
                m_packet.addInt(i);

            byte count = 0;
            for (int i = 0; i < 73; i++)
                if (obj.Inventory.Slots[i] != null)
                    count++;

            m_packet.addByte(count);

            for (int i = 0; i < 73; i++)
            {
                if (obj.Inventory.Slots[i] != null)
                {
                    m_packet.addByte((byte)i);
                    m_packet.addInt(i);
                    m_packet.addItem(obj.Inventory.Slots[i]);
                }
            }

            for (int i = 0; i < 73; i++)
                m_packet.addInt(i);

            // partie banque
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 42; j++)
                    m_packet.addInt(j);

                m_packet.addByte(0);

                for (int j = 0; j < 42; j++)
                    m_packet.addInt(j);
            }

            m_packet.addInt(-1); // pet buff

            m_packet.addByte(1);
            for (int i = 0; i < 6; i++)
                m_packet.addInt(i);

            m_packet.addByte(0);
            for (int i = 0; i < 6; i++)
                m_packet.addInt(i);

            m_packet.addInt(0);
            m_packet.addInt(0);

            m_packet.addByte(0); // premium bag 1
            m_packet.addByte(0); // premium bag 2

            m_packet.addInt(0); // 1 si le joueur ne peut pas parler

            // titres honorifiques
            for (int i = 0; i < 150; i++)
                m_packet.addInt(0);

            m_packet.addInt(0);
            m_packet.addInt(0);
            m_packet.addInt(0);

            _finish();

            return m_packet;
        }

        public static CPacket spawn(CWorldObject obj)
        {
            _startShared(0);

            bool isMover = false;

            switch (obj.Type)
            {
                case ObjType.Player:
                    {
                        isMover = true;

                        CPlayerObject playerObj = (CPlayerObject)obj;
                        CCharacter character = playerObj.Player.Character;

                        _addPart(playerObj.ID, Part.Spawn);

                        m_packet.addByte(5); // type d'objet
                        m_packet.addInt(character.Sex == Sex.Female ? 12 : 11); // model
                        m_packet.addByte(5); // type d'objet
                        m_packet.addInt(character.Sex == Sex.Female ? 12 : 11);  // model
                        m_packet.addShort(playerObj.Size); // taile (multipliée par 100)
                        m_packet.addPosition(playerObj.Position); // position
                        m_packet.addShort(playerObj.Rotation); // rotation
                        m_packet.addInt(playerObj.ID); // ID de l'objet

                        m_packet.addShort(1); // motion
                        m_packet.addByte(1); // est un joueur
                        m_packet.addInt(playerObj.HP); // HP

                        m_packet.addInt(1);
                        m_packet.addInt(0);
                        m_packet.addByte(0);

                        m_packet.addInt(-1); // v15 : Sfx

                        m_packet.addString(character.Name); // nom du perso
                        m_packet.addByte((byte)character.Sex); // sexe (masculin = 0|féminin = 1)
                        m_packet.addByte(0); // skinset -> semble ne plus être utilisé
                        m_packet.addByte(character.Hair); // ID des cheveux
                        m_packet.addInt(character.HairColor); // couleur des cheveux
                        m_packet.addByte(character.Head); // ID de la tête
                        m_packet.addInt(character.ID); // ID du perso
                        m_packet.addByte(character.Job); // classe
                        m_packet.addShort((short)character.FOR); // STR
                        m_packet.addShort((short)character.END); // STA
                        m_packet.addShort((short)character.DEX); // DEX
                        m_packet.addShort((short)character.INT); // INT
                        m_packet.addShort((short)character.Level); // level

                        m_packet.addInt(-1);
                        m_packet.addInt(0);
                        m_packet.addByte(0);

                        m_packet.addInt(0);
                        m_packet.addByte(0);
                        m_packet.addByte((byte)playerObj.Player.Account.AccessLevel);
                        m_packet.addInt(0); // flags
                        m_packet.addInt(0); // state mode
                        m_packet.addInt(0x000001F6); // ???
                        m_packet.addInt(0); // PK time
                        m_packet.addInt(0); // PK
                        m_packet.addInt(0); // PK propensity
                        m_packet.addInt(0); // PK exp
                        m_packet.addInt(0); // réputation
                        m_packet.addByte(0); // si 1 le joueur est en duel
                        m_packet.addInt(-1); // titre honorifique

                        CInventory inv = playerObj.Inventory;

                        byte count = 0;
                        for (int i = 42; i < 73; i++)
                        {
                            if (inv.Slots[i] == null)
                            {
                                m_packet.addInt(0);
                            }
                            else
                            {
                                count++;

                                m_packet.addByte(0); // refine
                                m_packet.addByte(0);
                                m_packet.addByte(0); // element
                                m_packet.addByte(0); // element refine
                            }
                        }

                        for (int i = 0; i < 28; i++)
                            m_packet.addInt(0);

                        m_packet.addByte(count);

                        for (int i = 42; i < 73; i++)
                        {
                            if (inv.Slots[i] != null)
                            {
                                m_packet.addByte((byte)(i - 42));
                                m_packet.addShort((short)inv.Slots[i].Prop.ID);
                                m_packet.addByte(0);
                            }
                        }

                        m_packet.addInt(-1);
                        m_packet.addInt(0);
                        m_packet.addInt(0);
                    }
                    break;

                case ObjType.Drop:
                    {
                        CDropObject drop = (CDropObject)obj;

                        _addPart(drop.ID, Part.Spawn);

                        m_packet.addByte(4); // type d'objet
                        m_packet.addInt(drop.ItemProp.ID); // model
                        m_packet.addByte(4); // type d'objet
                        m_packet.addInt(drop.ItemProp.ID);  // model
                        m_packet.addShort(drop.Size); // taile (multipliée par 100)
                        m_packet.addPosition(drop.Position); // position
                        m_packet.addShort(drop.Rotation); // rotation
                        m_packet.addInt(drop.ID); // ID de l'objet

                        m_packet.addInt(-1);

                        m_packet.addInt(drop.ItemProp.ID);
                        m_packet.addInt(0);
                        m_packet.addInt(0);

                        m_packet.addShort(1);

                        m_packet.addByte(0);

                        m_packet.addInt(0);
                        m_packet.addInt(0);

                        m_packet.addByte(0);

                        m_packet.addInt(0);
                        m_packet.addInt(0);

                        m_packet.addByte(0);

                        m_packet.addInt(0);
                        m_packet.addInt(0);
                        m_packet.addInt(0);

                        m_packet.addInt(0);
                        m_packet.addInt(0);

                        m_packet.addLong(0);
                        m_packet.addLong(0);

                        m_packet.addByte(0);
                        m_packet.addInt(0);
                    }
                    break;

                case ObjType.Monster:
                    {
                        isMover = true;

                        CMonster mob = (CMonster)obj;

                        _addPart(mob.ID, Part.Spawn);

                        m_packet.addByte(5); // type d'objet
                        m_packet.addInt(mob.MoverProp.ID); // model
                        m_packet.addByte(5); // type d'objet
                        m_packet.addInt(mob.MoverProp.ID);  // model
                        m_packet.addShort(mob.Size); // taile (multipliée par 100)
                        m_packet.addPosition(mob.Position); // position
                        m_packet.addShort(mob.Rotation); // rotation
                        m_packet.addInt(mob.ID); // ID de l'objet

                        m_packet.addShort(1); // motion
                        m_packet.addByte(0); // est un joueur
                        m_packet.addInt(mob.HP); // HP

                        m_packet.addInt(1);
                        m_packet.addInt(0);
                        m_packet.addByte(0);

                        m_packet.addInt(-1); // v15 : Sfx

                        m_packet.addByte(0); // hairId
                        m_packet.addInt(-1); // hairColor
                        m_packet.addByte(0); // head
                        m_packet.addInt(0); // nom
                        m_packet.addByte(0); // nombre d'items

                        m_packet.addByte((byte)(mob.Aggro ? 1 : 0)); // aggro

                        m_packet.addByte(0);
                        m_packet.addByte(0);
                        m_packet.addInt(0);
                        m_packet.addFloat(1.0f); // vitesse
                        m_packet.addInt(0); // buffs
                    }
                    break;

                case ObjType.Npc:
                    {
                        isMover = true;

                        CNPCObject npc = (CNPCObject)obj;

                        _addPart(npc.ID, Part.Spawn);

                        m_packet.addByte(5); // type d'objet
                        m_packet.addInt(npc.MoverProp.ID); // model
                        m_packet.addByte(5); // type d'objet
                        m_packet.addInt(npc.MoverProp.ID);  // model
                        m_packet.addShort(npc.Size); // taile (multipliée par 100)
                        m_packet.addPosition(npc.Position); // position
                        m_packet.addShort(npc.Rotation); // rotation
                        m_packet.addInt(npc.ID); // ID de l'objet

                        m_packet.addShort(1); // motion
                        m_packet.addByte(0); // est un joueur
                        m_packet.addInt(1); // peut être selectionné

                        m_packet.addInt(1);
                        m_packet.addInt(0);
                        m_packet.addByte(1);

                        m_packet.addInt(-1); // v15 : Sfx

                        m_packet.addByte(0); // hairId
                        m_packet.addInt(-1); // hairColor
                        m_packet.addByte(0); // head
                        m_packet.addString(npc.Name); // nom
                        m_packet.addByte(0); // nombre d'items

                        m_packet.addByte(0); // aggro

                        m_packet.addByte(0);
                        m_packet.addByte(0);
                        m_packet.addInt(0);
                        m_packet.addFloat(1.0f); // vitesse
                        m_packet.addInt(0); // buffs
                    }
                    break;

                case ObjType.Ctrl:
                    {
                        CControlObject ctrl = (CControlObject)obj;

                        _addPart(ctrl.ID, Part.Spawn);

                        m_packet.addByte(2); // type d'objet
                        m_packet.addInt(ctrl.PropID); // model
                        m_packet.addByte(2); // type d'objet
                        m_packet.addInt(ctrl.PropID);  // model
                        m_packet.addShort(ctrl.Size); // taile (multipliée par 100)
                        m_packet.addPosition(ctrl.Position); // position
                        m_packet.addShort(ctrl.Rotation); // rotation
                        m_packet.addInt(ctrl.ID); // ID de l'objet

                        m_packet.addInt(ctrl.PropID); // pas sûr
                    }
                    break;
            }

            if (isMover)
            {
                CMover mover = (CMover)obj;

                if (mover.IsMoving)
                {
                    _addPart(mover.ID, Part.ObjectWalk);

                    m_packet.addPosition(mover.TargetPos);
                    m_packet.addByte(1);
                }
            }

            _finish();

            return m_packet;
        }

        public static CPacket worldReadInfo(CWorldObject obj)
        {
            _startShared(0);

            _addPart(obj.ID, Part.WorldReadInfo);

            m_packet.addInt(obj.World.ID);
            m_packet.addPosition(obj.Position);

            _finish();

            return m_packet;
        }

        public static CPacket positionUpdate(CWorldObject obj)
        {
            _startShared(0);

            _addPart(obj.ID, Part.Teleport);

            m_packet.addPosition(obj.Position);

            _finish();

            return m_packet;
        }

        public static CPacket despawn(CWorldObject obj)
        {
            _startShared(0);

            _addPart(obj.ID, Part.Despawn);

            _finish();

            return m_packet;
        }

        public static CPacket teleportWorld(CWorldObject obj)
        {
            _startShared(0);

            _addPart(obj.ID, Part.TeleportWorld);
            m_packet.addInt(obj.World.ID);
            m_packet.addPosition(obj.Position);

            _finish();

            return m_packet;
        }

        public static CPacket objectWalking(CMover mover)
        {
            _startShared(0);

            _addPart(mover.ID, Part.ObjectWalk);

            m_packet.addPosition(mover.TargetPos);
            m_packet.addByte(1);

            _finish();

            return m_packet;
        }

        public static CPacket follow(CMover mover)
        {
            _startShared(0);

            _addPart(mover.ID, Part.ObjectFollow);

            m_packet.addInt(mover.Followed.ID);
            m_packet.addFloat(1.0f);

            _finish();

            return m_packet;
        }

        public static CPacket chat(int sender, string msg)
        {
            _startShared(sender);

            _addPart(sender, Part.MoverChat);

            m_packet.addString(msg);

            _finish();

            return m_packet;
        }

        public static CPacket greenText(string msg)
        {
            _startShared(0);

            _addPart(-1, Part.GreenText);

            m_packet.addByte(1);
            m_packet.addString(msg);

            _finish();

            return m_packet;
        }

        public static CPacket greeting(int id)
        {
            _start(LoginCommand.Greeting);

            m_packet.addInt(id);

            _finish();

            return m_packet;
        }

        public enum LoginError
        {
            OldClient = (int)107L,
            WrongUsername = (int)121L,
            WrongPassword = (int)120L,
            Banned = (int)132L,
            NameInUse = 0x0524,
            WrongPasswordToDelChar = 0x527,
            AlreadyConnected = 0x67
        }

        public static CPacket error(LoginError error)
        {
            _start(LoginCommand.Error);

            m_packet.addInt((int)error);

            _finish();

            return m_packet;
        }

        public static CPacket serverList(string username, CServerList list)
        {
            _start(LoginCommand.ServerList);

            m_packet.addInt(0);
            m_packet.addByte(0);

            m_packet.addString(username.ToLower());

            m_packet.addInt(2);

            m_packet.addInt(-1);
            m_packet.addInt(0);
            m_packet.addString(list.ServerName);
            m_packet.addString(list.ServerIP);
            m_packet.addInt(0);
            m_packet.addInt(0);
            m_packet.addInt(1);
            m_packet.addInt(0);

            m_packet.addInt(0);
            m_packet.addInt(1);
            m_packet.addString(list.ChannelName);
            m_packet.addString(list.ChannelIP);
            m_packet.addInt(0);
            m_packet.addInt(0);
            m_packet.addInt(1);
            m_packet.addInt(100);

            _finish();

            return m_packet;
        }

        public static CPacket channelIp(string ip)
        {
            _start(CharCommand.ChannelIP);

            m_packet.addString(ip);

            _finish();

            return m_packet;
        }

        public static CPacket charList(CCharPlayer player)
        {
            _start(CharCommand.CharList);

            m_packet.addInt(0);

            int charCount = 0;
            for (int i = 0; i < 3; i++)
                if (player.Characters[i] != null)
                    charCount++;

            CCharCharacter character;

            m_packet.addInt(charCount);
            for (int i = 0; i < 3; i++)
            {
                character = player.Characters[i];

                if (character != null)
                {
                    m_packet.addInt(i);
                    m_packet.addInt(1);
                    m_packet.addInt(1);
                    m_packet.addInt(0x0b);
                    m_packet.addString(character.Name);

                    m_packet.addByte(0x0e);
                    m_packet.addByte(0xa6);
                    m_packet.addByte(0xd9);
                    m_packet.addByte(0x45);

                    m_packet.addByte(0xa5);
                    m_packet.addByte(0x79);
                    m_packet.addByte(0xc8);
                    m_packet.addByte(0x42);

                    m_packet.addByte(0x3f);
                    m_packet.addByte(0x58);
                    m_packet.addByte(0x49);
                    m_packet.addByte(0x45);

                    m_packet.addInt(character.ID);
                    m_packet.addInt(0);
                    m_packet.addInt(0);
                    m_packet.addInt(0);
                    m_packet.addInt(0);

                    m_packet.addInt(character.Hair);
                    m_packet.addInt(character.HairColor);
                    m_packet.addInt(character.Head);
                    m_packet.addByte(character.Sex);
                    m_packet.addInt(character.Job);
                    m_packet.addInt(character.Level);
                    m_packet.addInt(0);
                    m_packet.addInt(character.FOR);
                    m_packet.addInt(character.END);
                    m_packet.addInt(character.DEX);
                    m_packet.addInt(character.INT);
                    m_packet.addInt(0);

                    m_packet.addInt(character.Equipment.Count);
                    foreach (int item in character.Equipment)
                        m_packet.addInt(item);
                }
            }

            m_packet.addInt(charCount);
            for (int i = 0; i < 3; i++)
            {
                if (player.Characters[i] != null)
                {
                    m_packet.addInt(0);
                    m_packet.addInt(0);
                    m_packet.addInt(0);
                    m_packet.addByte(0);
                }
            }

            _finish();

            return m_packet;
        }

        public static CPacket worldConfirmation(CCharPlayer player, int charSlot)
        {
            _start(CharCommand.WorldConfirmation);

            m_packet.addInt(player.ID);

            m_packet.addString(player.Account.Username);

            m_packet.addInt(player.Characters[charSlot].ID);

            m_packet.addString(player.Characters[charSlot].Name);

            m_packet.addByte(1);

            _finish();

            return m_packet;
        }

        private static void _start(LoginCommand cmd)
        {
            m_packet.clear();

            m_packet.addByte(0x5e);
            m_packet.addInt(0); // taille du packet
            m_packet.addInt((int)cmd);
        }

        private static void _start(CharCommand cmd)
        {
            m_packet.clear();

            m_packet.addByte(0x5e);
            m_packet.addInt(0); // taille du packet
            m_packet.addInt((int)cmd);
        }

        private static void _start(GameCommand cmd)
        {
            m_packet.clear();

            m_packet.addByte(0x5e);
            m_packet.addInt(0); // taille du packet
            m_packet.addInt((int)cmd);
        }

        private static void _startShared(int id)
        {
            _startShared(id, 0xffffff00);
        }

        private static void _startShared(int id, GameCommand cmd)
        {
            _startShared(id, (uint)cmd);
        }

        private static void _startShared(int id, uint cmd)
        {
            m_packet.clear();

            m_packet.addByte(0x5e);
            m_packet.addInt(0); // taille du packet
            m_packet.addInt((int)cmd);

            m_packet.addInt(id);
            m_packet.addShort(0); // nombre de parties
        }

        private static void _addPart(int id, Part part)
        {
            m_packet.setShort(13, (short)(m_packet.getShort(13) + 1));

            m_packet.addInt(id);
            m_packet.addShort((short)part);
        }

        private static void _finish()
        {
            m_packet.setInt(1, m_packet.Lenght - 5);
        }

        private static CPacket m_packet = new CPacket();

        private enum LoginCommand
        {
            Greeting = 0,
            Error = 0x000000fe,
            ServerList = 0x000000fd
        }

        private enum CharCommand
        {
            CharList = 0x000000f3,
            ChannelIP = 0x000000f2,
            WorldConfirmation = 0x0000ff05
        }

        private enum GameCommand
        {
            Greeting = 0x00,
            Notice = 0xff00ea,
            PrivateMessage = 0xff00e0
        }

        private enum Part
        {
            MoverChat = 0x0001,
            Spawn = 0x00f0,
            Despawn = 0x00f1,
            Teleport = 0x0010,
            TeleportWorld = 0x00f2,
            ObjectWalk = 0x00c1,
            ObjectFollow = 0x000000c2,
            WorldReadInfo = 0x9910,
            GreenText = 0x000000a0,
            AttackMotion = 0x00e0,
            Damage = 0x0013,
            MoverDeath = 0x00c7,
            WeatherNormal = 0x0060,
            WeatherSnow = 0x0061,
            WeatherRain = 0x0062,
            InventoryMoveItem = 0x0004,
            InventoryUpdateItem = 0x0018,
            Revival = 0x00a2,
            LevelInfos = 0x0012
        }
    }
}